package com.zjcloud.jwgl.algorithm;

import com.zjcloud.jwgl.domain.ScheduleGene;
import com.zjcloud.jwgl.domain.CourseArrangement;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 遗传算法工具类，用于智能排课
 */
public class GeneticAlgorithmUtil {
    
    private static final Random random = new Random();
    
    /**
     * 初始化种群
     * 
     * @param courseIds 需要排课的课程ID列表
     * @return 初始化的种群
     */
    public static List<ScheduleGene> initPopulation(List<Long> courseIds) {
        List<ScheduleGene> population = new ArrayList<>();
        
        // 创建初始种群（100个个体）
        for (int i = 0; i < 100; i++) {
            List<CourseArrangement> arrangements = new ArrayList<>();
            
            // 为每个课程随机分配时间和地点
            for (Long courseId : courseIds) {
                CourseArrangement arrangement = new CourseArrangement();
                arrangement.setCourseId(courseId);
                arrangement.setTeacherId(getRandomTeacherId()); // 随机分配教师
                arrangement.setClassroomId(getRandomClassroomId()); // 随机分配教室
                arrangement.setClassId(getRandomClassId()); // 随机分配班级
                arrangement.setWeekDay(random.nextInt(5) + 1); // 周一到周五
                arrangement.setLessonNo(random.nextInt(8) + 1); // 第1-8节课
                arrangement.setStatus("0"); // 正常状态
                
                arrangements.add(arrangement);
            }
            
            ScheduleGene gene = new ScheduleGene(arrangements);
            population.add(gene);
        }
        
        return population;
    }
    
    /**
     * 进化种群
     * 
     * @param population 当前种群
     * @return 进化后的种群
     */
    public static List<ScheduleGene> evolve(List<ScheduleGene> population) {
        List<ScheduleGene> newPopulation = new ArrayList<>();
        
        // 保留精英（前10个个体）
        for (int i = 0; i < 10; i++) {
            newPopulation.add(population.get(i));
        }
        
        // 交叉操作生成新个体
        for (int i = 0; i < 45; i++) {
            ScheduleGene parent1 = selectParent(population);
            ScheduleGene parent2 = selectParent(population);
            ScheduleGene child = crossover(parent1, parent2);
            newPopulation.add(child);
        }
        
        // 变异操作生成新个体
        for (int i = 0; i < 45; i++) {
            ScheduleGene parent = selectParent(population);
            ScheduleGene child = mutate(parent);
            newPopulation.add(child);
        }
        
        return newPopulation;
    }
    
    /**
     * 选择父代个体
     * 
     * @param population 种群
     * @return 选中的个体
     */
    private static ScheduleGene selectParent(List<ScheduleGene> population) {
        // 简单实现：随机选择前50%的个体作为父代
        int index = random.nextInt(population.size() / 2);
        return population.get(index);
    }
    
    /**
     * 交叉操作
     * 
     * @param parent1 父代1
     * @param parent2 父代2
     * @return 子代
     */
    private static ScheduleGene crossover(ScheduleGene parent1, ScheduleGene parent2) {
        List<CourseArrangement> arrangements1 = parent1.getArrangements();
        List<CourseArrangement> arrangements2 = parent2.getArrangements();
        List<CourseArrangement> childArrangements = new ArrayList<>();
        
        // 单点交叉
        int crossPoint = random.nextInt(arrangements1.size());
        
        for (int i = 0; i < arrangements1.size(); i++) {
            if (i < crossPoint) {
                childArrangements.add(clone(arrangements1.get(i)));
            } else {
                childArrangements.add(clone(arrangements2.get(i)));
            }
        }
        
        return new ScheduleGene(childArrangements);
    }
    
    /**
     * 变异操作
     * 
     * @param parent 父代
     * @return 变异后的子代
     */
    private static ScheduleGene mutate(ScheduleGene parent) {
        List<CourseArrangement> arrangements = new ArrayList<>();
        
        // 复制父代安排
        for (CourseArrangement arr : parent.getArrangements()) {
            arrangements.add(clone(arr));
        }
        
        // 随机选择一个课程进行变异
        int mutateIndex = random.nextInt(arrangements.size());
        CourseArrangement arrangement = arrangements.get(mutateIndex);
        
        // 随机变异一个属性
        int mutateType = random.nextInt(3);
        switch (mutateType) {
            case 0:
                arrangement.setWeekDay(random.nextInt(5) + 1); // 变异星期
                break;
            case 1:
                arrangement.setLessonNo(random.nextInt(8) + 1); // 变异节次
                break;
            case 2:
                arrangement.setClassroomId(getRandomClassroomId()); // 变异教室
                break;
        }
        
        return new ScheduleGene(arrangements);
    }
    
    /**
     * 克隆课程安排对象
     * 
     * @param original 原始对象
     * @return 克隆后的对象
     */
    private static CourseArrangement clone(CourseArrangement original) {
        CourseArrangement clone = new CourseArrangement();
        clone.setCourseId(original.getCourseId());
        clone.setTeacherId(original.getTeacherId());
        clone.setClassroomId(original.getClassroomId());
        clone.setClassId(original.getClassId());
        clone.setWeekDay(original.getWeekDay());
        clone.setLessonNo(original.getLessonNo());
        clone.setStatus(original.getStatus());
        return clone;
    }
    
    /**
     * 计算适应度
     * 
     * @param gene 基因
     * @param redisTemplate Redis模板
     * @return 计算适应度后的基因
     */
    public static ScheduleGene calculateFitness(ScheduleGene gene, RedisTemplate<String, Object> redisTemplate) {
        double fitness = 100.0; // 初始适应度为100
        
        List<CourseArrangement> arrangements = gene.getArrangements();
        
        // 检查各种冲突并扣分
        for (int i = 0; i < arrangements.size(); i++) {
            CourseArrangement arr1 = arrangements.get(i);
            
            // 检查与其他课程的冲突
            for (int j = i + 1; j < arrangements.size(); j++) {
                CourseArrangement arr2 = arrangements.get(j);
                
                // 教师时间冲突
                if (arr1.getTeacherId().equals(arr2.getTeacherId()) && 
                    arr1.getWeekDay().equals(arr2.getWeekDay()) && 
                    arr1.getLessonNo().equals(arr2.getLessonNo())) {
                    fitness -= 10.0;
                }
                
                // 教室时间冲突
                if (arr1.getClassroomId().equals(arr2.getClassroomId()) && 
                    arr1.getWeekDay().equals(arr2.getWeekDay()) && 
                    arr1.getLessonNo().equals(arr2.getLessonNo())) {
                    fitness -= 10.0;
                }
                
                // 班级时间冲突
                if (arr1.getClassId().equals(arr2.getClassId()) && 
                    arr1.getWeekDay().equals(arr2.getWeekDay()) && 
                    arr1.getLessonNo().equals(arr2.getLessonNo())) {
                    fitness -= 10.0;
                }
            }
        }
        
        // 设置适应度
        gene.setFitness(Math.max(0, fitness));
        return gene;
    }
    
    // 模拟方法，实际项目中应该从数据库获取
    private static Long getRandomTeacherId() {
        return 100L + random.nextInt(20);
    }
    
    private static Long getRandomClassroomId() {
        return 200L + random.nextInt(30);
    }
    
    private static Long getRandomClassId() {
        return 300L + random.nextInt(10);
    }
}